table of contents
stdarg(3) | 2007-10-27-16:31 | stdarg(3) |
Назва¶
stdarg - змінний список аргументів
Огляд¶
#include <stdarg.h>
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
Опис¶
Функція може бути викликаною з різноманітною кількістю аргументів різноманітних типів. Файл-заголовок stdarg.h оголошує тип va_list і визначає три макроси для проходження через список аргументів, чия кількість і тип невідомі викликаній функції.
Викликана функція повинна оголосити об'єкт типу va_list, який використовуватиметься макросами va_start, va_arg і va_end.
va_start ¶
Макрос va_start ініціалізує ap для пізнішого використання va_arg і va_end і повинен бути викликаним першим.
Параметр last є назвою останнього параметру перед змінним списком аргументів, тобто останній параметр, чий тип відомий викликаючій функції.
Оскільки адреса цього параметру може використовуватись у va_start макросі, її не слід оголошувати як регістрова змінна, або як функція, або ж як масивовий тип.
va_arg ¶
Макрос va_arg розкривається у вираз, що матиме тип і значення наступного аргумету виклику. Параметр ap є типу va_list, ініційований va_start. Кожний виклик va_arg змінює ap так, що кожний новий виклик повертає наступний аргумент. Параметр type є назвою типу, тож покажчик на об'єкт певного типу можна вказати просто додаючи * за вказаним типом.
Перше використання макросу va_arg після va_start повертає аргумент, що слідує за останнім відомим аргументом, last. Послідовні виклики повертають значення решти аргументів.
Якщо наступний аргумент відсутній або, якщо тип є несумісним з типом дійсного наступного аргументу, відбудеться довільна помилка.
Якщо ap передано функції, що використовує va_arg(ap, type), тоді значення ap буде невизначеним після повернення цією функцією.
va_end ¶
Кожний виклик va_start повинен мати відповідний va_end у тій самій функції. Після виклику va_end(ap) змінна ap стане невизначеною. Можливі багатократні проходження списків, кожне з яких повинно бути включеним у va_start і va_end. va_end може бути як макросом, так і функцією.
va_copy ¶
Стандартна реалізація, як правило, має va_list як покажчик на фрейм стеку зміцнювальної функції. При такій (найпоширенішій) схемі, схоже, нічого не заперечує присвоєнню на зразок
va_list aq = ap;
va_list aq;
*aq = *ap;
va_list aq;
va_copy(aq, ap);
...
va_end(aq);
Приклад¶
Функція sum, яка додає довільну кількість цілих.
#include<stdarg.h>
#include<stdio.h>
void sum(char *, int, ...);
int main(void)
{
sum("The sum of 10+15+13 is %d.\n", 3, 10, 15, 13);
return 0;
}
void sum(char *string, int num_args, ...)
{
int sum = 0;
va_list ap;
int i;
va_start(ap, num_args); /* ініціалізація ap */
for(i = 0; i < num_args; i++)
sum += va_arg(ap, int); /* проходження ap *
* через аргументи */
printf(string, sum);
va_end(ap);
}
#include <stdio.h>
#include <stdarg.h>
void fprint(char *fmt, ...) {
va_list ap;
int d;
char c, *p, *s;
va_start(ap, fmt);
while (*fmt)
switch(*fmt++) {
case 's': /* ланцюжок */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* ціле int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* символ char */
/* необхідне зведення типів, оскільки va_arg *
* візьме тільки повністю сформований тип */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
Відповідність стандартам¶
Макроси va_start, va_arg і va_end відповідають ANSI X3.159-1989 ("C89"). C99 дало визначення макросу va_copy.
Сумісність¶
Ці макроси не сумісні з історичними версіями, які вони замінили. Обернено-сумісну версію можна знайти у заголовковому файлі varargs.h.
Порівняння¶
Історична версія виглядатиме наступним чином:
#include <varargs.h>
void fprint(va_alist) va_dcl {
va_list ap;
va_start(ap);
while(...) {
...
x = va_arg(ap, type);
...
}
va_end(ap);
}
Вади¶
На відміну від макросів varargs.h, розглянуті тут не дозволяють програмістам кодування функцій без сталих аргументів. Ця проблема додає роботи, головним чином, коли доводиться переводити код varargs до stdarg, але це також створює труднощі у випадку змінювальних функцій, які хочуть передати всі свої аргументи іншій, яка візьме аргументи типу va_list, наприклад vfprintf(3).
2007-10-27-16:31 | © 2005-2007 DLOU, GNU FDL |